<!DOCTYPE html>
<!-- saved from url=(0097)https://www.codeproject.com/Articles/617212/Custom-Controls-in-Win-API-The-Painting?display=Print -->
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>Custom Controls in Win32 API: The Painting - CodeProject</title> 
	<link type="text/css" rel="stylesheet" href="./Custom Controls in Win32 API_ The Painting - CodeProject_files/Main.min.css">

	
<meta http-equiv="content-language" content="en-US">

<meta name="Description" content="Understanding the basics of custom control painting and avoiding the trap of control flicker; Author: Martin Mitáš; Updated: 12 Dec 2014; Section: Windows API; Chapter: Platforms, Frameworks &amp; Libraries; Updated: 12 Dec 2014">
<meta name="Keywords" content="C, Windows, Win32, Win64, Visual-Studio, Dev, VS2010, custom-controls,Windows API,Platforms, Frameworks &amp; Libraries,Free source code, tutorials">
<meta name="Author" content="Martin Mitáš">
<meta name="Rating" content="General">
<meta name="Revisit-After" content="1 days">
<meta name="application-name" content="CodeProject">
<meta name="google-translate-customization" content="d908bb7ce7aff658-4c2f3a504525c916-g629383f736781a8a-13">

<link rel="dns-prefetch" href="https://ajax.googleapis.com/"> 
<link rel="canonical" href="https://www.codeproject.com/Articles/617212/%2fArticles%2f617212%2fCustom-Controls-in-Win-API-The-Painting">
<link rel="alternate" type="application/rss+xml" title="CodeProject Latest articles - All Topics" href="https://www.codeproject.com/WebServices/ArticleRSS.aspx?cat=1">
<link rel="alternate" type="application/rss+xml" title="CodeProject Latest articles - Artificial Intelligence" href="https://www.codeproject.com/WebServices/ArticleRSS.aspx?cat=31">
<link rel="alternate" type="application/rss+xml" title="CodeProject Lounge Postings" href="https://www.codeproject.com/webservices/LoungeRSS.aspx">
<meta name="robots" content="index, follow">
<link rel="search" type="application/opensearchdescription+xml" title="CodeProject" href="https://www.codeproject.com/info/OpenSearch.xml">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<link rel="apple-touch-icon" sizes="144x144" href="https://www.codeproject.com/favicon/apple-touch-icon.png"> 
<link rel="icon" type="image/png" sizes="32x32" href="https://www.codeproject.com/favicon/favicon-32x32.png"> 
<link rel="icon" type="image/png" sizes="16x16" href="https://www.codeproject.com/favicon/favicon-16x16.png"> 
<link rel="manifest" href="https://www.codeproject.com/favicon/manifest.json"> 
<link rel="mask-icon" href="https://www.codeproject.com/favicon/safari-pinned-tab.svg" color="#ff9900">
	
<script type="application/ld+json">
{
  "@context": "http://schema.org",
  "@type": "TechArticle",
  "headline": "Custom Controls in Win32 API: The Painting",
  "url": "https://www.codeproject.com/Articles/617212/Custom-Controls-in-Win-API-The-Painting",
  "discussionUrl": "https://www.codeproject.com/Articles/617212/Custom-Controls-in-Win-API-The-Painting",
  "isFamilyFriendly": "true",
  "image": "https://codeproject.global.ssl.fastly.net/App_Themes/CodeProject/Img/Article100.png",
  "keywords": "C, Windows, Win32, Win64, Visual-Studio (VS2010), custom-controls",
  "commentCount": "24",
  "editor" : {
    "@type" : "Person",
    "name" : "Martin Mitáš",
    "url" : "https://www.codeproject.com/script/Membership/View.aspx?mid=5807385"
  },
  "license": "http://www.codeproject.com/info/cpol10.aspx",
  "publisher" : {
    "@type" : "Organization",
    "name" : "CodeProject"
  }
  "description": "Understanding the basics of custom control painting and avoiding the trap of control flicker",
  "upvoteCount": "52",
  "articleSection": "Windows API",
  "author" : [{
      "@type" : "Person",
      "name" : "Martin Mitáš",
      "url" : "https://www.codeproject.com/script/Membership/View.aspx?mid=5807385"
    }],
  "datePublished": "2013-07-14",
  "dateCreated": "2013-07-14",
  "dateModified": "2014-12-12",
  "aggregateRating" : {
    "@type" : "aggregateRating",
    "ratingValue" : 4.99,
    "ratingCount" : 52,
    "bestRating" : 5,
    "worstRating" : 1
  },
}
</script>
<script type="application/ld+json">
{
  "@context": "http://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [{
    "@type": "ListItem",
    "position": 1,
    "item" : {
      "@id" : "/Chapters/8/Platforms-Frameworks-Libraries.aspx",
      "name" : "Platforms, Frameworks & Libraries"
    }
  },{
    "@type": "ListItem",
    "position": 2,
    "item" : {
      "@id" : "/KB/vista/",
      "name" : "Windows API"
    }
  }]
}
</script>
	<!--<base target="_top">--><base href="." target="_top">
	<script type="text/javascript" src="./Custom Controls in Win32 API_ The Painting - CodeProject_files/jquery.2.2.4.min.js.下载"></script><script type="text/javascript">//<![CDATA[
if (typeof jQuery == 'undefined') {
    document.write(unescape("%3Cscript src='%2fscript%2fJS%2fjquery-2.2.4.min.js' type='text/javascript' %3E%3C/script%3E"));
}//]]></script><script src="./Custom Controls in Win32 API_ The Painting - CodeProject_files/jquery-2.2.4.min.js.下载" type="text/javascript"></script>
<script type="text/javascript">//<![CDATA[
function defrm () { /* thanks twitter */ document.write = ''; window.top.location = window.self.location;  setTimeout(function() { document.body.innerHTML = ''; }, 0);  window.self.onload = function(evt) { document.body.innerHTML = ''; }; }if (window.top !== window.self) {  try {  if (window.top.location.host) { /* will throw */ } else { defrm(); /* chrome */ }  } catch (ex) { defrm(); /* everyone else */ } }if (typeof(DemoUrl)!='undefined')   document.write(unescape('%3Cme')+'ta http'+'-equiv="re'+'fresh"                  con'+'tent="1;url='+DemoUrl+unescape('"%3CE'));

//]]>
</script>

	




<script type="text/javascript">
	var _gaq = _gaq || [];
	_gaq.push(['_setAccount', 'UA-1735123-1']);
	_gaq.push(['_trackPageview']);
	_gaq.push(['_setDomainName', 'www.codeproject.com']);
	_gaq.push(['_setSessionTimeout', '1200']); 

	(function () {
		var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
		ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
		(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ga);
	})(); 
</script><script type="text/javascript" async="" src="./Custom Controls in Win32 API_ The Painting - CodeProject_files/ga.js.下载"></script>


</head>	

<body class="chrome chrome67 touch">

<a class="access-link" href="https://www.codeproject.com/Articles/617212/Custom-Controls-in-Win-API-The-Painting?display=Print#Main"><img alt="Click here to Skip to main content" src="./Custom Controls in Win32 API_ The Painting - CodeProject_files/t.gif"></a>





<div class="page-background">

	
	

	

	
    <div id="ctl00_STM" class="site-top-menu fluid">
        <div class="main-content">
            
        </div>
    </div>

	
    <div id="ctl00_SH" class="site-header fluid">
        <div class="main-content">
            <div class="logo"><a href="https://www.codeproject.com/"><img id="ctl00_Logo" tabindex="1" title="CodeProject" src="./Custom Controls in Win32 API_ The Painting - CodeProject_files/logo250x135.gif" alt="Home" style="height:135px;width:250px;border-width:0px;"></a></div>
            <div class="promo"></div>
        </div>
    </div>

	<a href="https://www.codeproject.com/Articles/617212/Custom-Controls-in-Win-API-The-Painting?display=Print#Main"><img alt="Click here to Skip to main content" class="access-link" src="./Custom Controls in Win32 API_ The Painting - CodeProject_files/t.gif"></a>

	
			
	

	<div id="A" class="container-content-wrap fluid print"> 
	<div class="container-content">


		<div class="clearfix">
			<div class="container-breadcrumb float-left ">
				<div><a href="https://www.codeproject.com/script/Content/SiteMap.aspx">Articles</a> » <a href="https://www.codeproject.com/Chapters/8/Platforms-Frameworks-Libraries.aspx">Platforms, Frameworks &amp; Libraries</a> » <a href="https://www.codeproject.com/KB/vista/">Windows API</a> » <a href="https://www.codeproject.com/KB/vista/#General">General</a></div>
			</div>

            <div class="float-left">
				
			</div>

			<div class="edit-links float-right">
				
			</div>

			<div class="article-nav float-right">
                
				
			</div>
		</div>

		<table class="extended container-article-parts" cellpadding="0" cellspacing="0">
        <tbody><tr valign="top">
		<td width="117px" class="article-wing-left">

			

		</td>
		<td>
			
			<div id="AT" class="container-article  fluid tight"> 

				<div class="article">

					<form name="aspnetForm" method="post" action="https://www.codeproject.com/Articles/617212/Custom-Controls-in-Win-API-The-Painting?display=Print" id="aspnetForm" style="margin:0;padding:0">
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="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">
</div>

<div>

	<input type="hidden" name="__VIEWSTATEGENERATOR" id="__VIEWSTATEGENERATOR" value="10C1FD69">
</div>

					
					 
					<div class="header">
					    <a name="Main"></a>

					    
					    <a name="_articleTop" id="_articleTop"></a>
					    <div class="title">
					        <h1 id="ctl00_ArticleTitle">Custom Controls in Win32 API: The Painting</h1>
					    </div>

                        <div style="height:34px">
					        
					        <div class="entry float-left">

                                <img src="./Custom Controls in Win32 API_ The Painting - CodeProject_files/58de2d085c17e28b8951315245dd408c.jpeg" id="ctl00_avatar" class="float-left avatar">

                                <div class="float-left">
                                    <div>
						                <span class="author"><a href="https://www.codeproject.com/script/Membership/View.aspx?mid=5807385" rel="author">Martin Mitáš</a></span>, 
						                <span class="date" title="Date last updated">
							            12 Dec 2014</span>
			                        </div>

                                    
						            
    						        	

                                </div>

    	                        	
                                <div class="float-left" style="margin: 25px 0 0 10px;">
	                                
	                            </div>
                         	    	
    
					        </div>

                            

						    <div id="ctl00_AdManagerWrap" class="float-right align-center">
                                
						    </div>

                        </div>

                        <div id="ctl00_description" class="summary">Understanding the basics of custom control painting and avoiding the trap of control flicker</div><span id="ctl00_thumbnailUrl" class="date" content="https://codeproject.global.ssl.fastly.net/script/Articles/Images/article100x80.png"></span>			

                    </div>
                    
					
					

					

					
					
					

						
					

					

						
						<div id="contentdiv" class="text">
						



<ul class="download">
	<li><a href="https://www.codeproject.com/KB/vista/617212/dblbuf.zip">Download custom control demonstrating the double buffering - 117.9 KB</a></li></ul>

<h2>Articles in this Series</h2>

<ul>
	<li><a href="http://www.codeproject.com/Articles/559385/Custom-Controls-in-Win32-API-The-Basics">Custom Controls in Win32 API: The Basics</a></li>	<li>Custom Controls in Win32 API: The Painting</li>	<li><a href="http://www.codeproject.com/Articles/620045/Custom-Controls-in-Win32-API-Visual-Styles">Custom Controls in Win32 API: Visual Styles</a></li>	<li><a href="http://www.codeproject.com/Articles/624495/Custom-Controls-in-Win32-API-Standard-Messages">Custom Controls in Win32 API: Standard Messages</a></li>	<li><a href="http://www.codeproject.com/Articles/646482/Custom-Controls-in-Win-API-Control-Customization">Custom Controls in Win32 API: Control Customization</a></li>	<li><a href="http://www.codeproject.com/Articles/744603/Custom-Controls-in-Win-API-Encapsulation-of-Cust">Custom Controls in Win32 API: Encapsulation of Customized Controls</a></li>	<li><a href="http://www.codeproject.com/Articles/1042516/Custom-Controls-in-Win-API-Scrolling">Custom Controls in Win32 API: Scrolling</a></li></ul>

<h2>Introduction</h2>

<p>In the <a href="http://www.codeproject.com/Articles/559385/Custom-Controls-in-Win32-API-The-Basics">previous article</a>, we learned the very basics of custom control implementation. Today, we take a closer look at control painting. This topic is quite important because successful controls must look nice and they must fit into the Windows environment. This task is not as simple as it sounds, especially if you consider that most applications support more than one particular Windows version, and that in the last 10 years, almost every Windows version changes the default visual appearance of its controls.</p>

<h2>Multiple Painting APIs</h2>

<p>Over time, Microsoft has provided many APIs for 2D graphics and painting. GDI (<em>GDI32.DLL</em>) is available since ancient times, and can be used everywhere. GDI+ (<em>GDIPLUS.DLL</em>) is part of Windows XP and newer (but a redistributable version of it can be downloaded from the Microsoft website). Direct2D is the newest and it is available only on Windows 7 and newer.</p>

<p>In general, the newer APIs are capable of better graphics (e.g., support for anti-aliasing, alpha channels, etc.) and have better performance characteristics (when used in the right way) as they can offload many tasks to the graphics card, while GDI operates mainly on the main system memory and on the CPU.</p>

<p>However, we will mainly stick with GDI, in this article as well as the following ones. For custom controls implementation it is usually sufficient, it works everywhere, and last but not least, the paint-related messages a control receives are GDI-centric due to historical reasons. Of course, using the newer painting APIs is possible but it is not the subject of our interest.</p>

<p>All that said, this article is not about GDI painting. There are plenty of resources on the net on that. On this site, the topic is quite thoroughly covered by Paul Watt:</p>

<ul>
	<li><a href="http://www.codeproject.com/Articles/1988/Guide-to-WIN32-Paint-for-beginners">Guide to Win32 Paint for Beginners</a></li>	<li><a href="http://www.codeproject.com/Articles/2078/Guide-to-WIN32-Paint-for-Intermediates">Guide to Win32 Paint for Intermediates</a></li>	<li><a href="http://www.codeproject.com/Articles/1944/Guide-to-WIN32-Regions">Guide to Win32 Regions</a></li>	<li><a href="http://www.codeproject.com/Articles/2095/A-Guide-to-WIN32-Clipping-Regions">A Guide to Win32 Clipping Regions</a></li>	<li><a href="http://www.codeproject.com/Articles/251892/Guide-to-Image-Composition-with-Win32-MsImg32-dll">Guide to Image Composition with Win32 MsImg32.dll</a></li>	<li><a href="http://www.codeproject.com/Articles/224754/Guide-to-Win32-Memory-DC">Guide to Win32 Memory DC</a> (good complementary reading to the Double Buffering presented here)</li></ul>

<h2>Hello World</h2>

<p>The preceding article already provided a code for a trivial control which was, of course, also capable of painting itself. Let's take a look at the painting code from that example once again. When the control's window procedure gets the message <code>WM_PAINT</code>, it was just calling our function, <code>CustomPaint()</code>:</p>

<pre lang="C++"><span class="code-keyword">static</span> <span class="code-keyword">void</span>
CustomPaint(HWND hwnd)
{
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rect;

    GetClientRect(hwnd, &amp;rect);

    hdc = BeginPaint(hwnd, &amp;ps);
    SetTextColor(hdc, RGB(<span class="code-digit">0</span>,<span class="code-digit">0</span>,<span class="code-digit">0</span>));
    SetBkMode(hdc, TRANSPARENT);
    DrawText(hdc, _T(<span class="code-string">"</span><span class="code-string">Hello World!"</span>), -<span class="code-digit">1</span>, &amp;rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
    EndPaint(hwnd, &amp;ps);
}

<span class="code-keyword">static</span> LRESULT CALLBACK
CustomProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    <span class="code-keyword">switch</span>(uMsg) {
        <span class="code-comment">//</span><span class="code-comment"> ...</span>

        <span class="code-keyword">case</span> WM_PAINT:
            CustomPaint(hwnd);
            <span class="code-keyword">return</span> <span class="code-digit">0</span>;
    }
    <span class="code-keyword">return</span> DefWindowProc(hwnd, uMsg, wParam, lParam);
}</pre>

<p>The code sample already presents the very basic principle: Whenever the control needs painting, the system sends message <code>WM_PAINT</code>. The handler (here the function <code>CustomPaint()</code>) gets the device context handle (<code>BeginPaint()</code>), then uses it to paint the control with GDI functions (here, it just draws the string <code>"Hello world"</code> to the middle of the control), and then releases all resources with <code>EndPaint()</code>.</p>

<p>So far, there is no issue. However for good painting of complex controls, we simply need better understanding of how things really work. Otherwise, you will probably find yourselves on some web forum, searching for an answer to the omnipresent question "How to prevent control flickering when it is being resized?"</p>

<p>Also, complex controls may have a need to paint in other times then when <code>WM_PAINT</code> is received, or they may even have a need to paint outside its client area, either into the control's non-client area, or completely outside of the control's area.</p>

<h2>The Big Picture</h2>

<p>So how are the things around <code>WM_PAINT</code> glued together? From a perspective of the control (or more generally, any window represented with a <code>HWND</code> handle), there are several important messages, not just the <code>WM_PAINT</code>, and also some other concepts tightly related to the control painting.</p>

<p>First of all, we have to answer the question which any attentive reader already asks: When does the system decide the control needs to be painted? For each <code>HWND</code>, the system manages its window <em>update region</em> (also known as <em>dirty region</em>). The region describes part of the window, whose content is invalid and needs repainting. When the region is not empty, the system knows the control (actually its part as defined by the region) needs repainting and it will eventually send the control the <code>WM_PAINT</code> when there is no other message in the message queue of the window's thread.</p>

<p>Normally, the system does not remember the contents of a window. For example, whenever a window is moved to the edge of the screen so part of it is behind the corner, or whenever it is obscured by another window, the actual contents of the window is lost. After the window becomes fully visible once again, the system adds the unveiled part of the window into the update region which then eventually leads to requesting its repainting.</p>

<p>The control may also need to repaint itself or its part because its state or the data it shows has changed. To do so, the control simply may call a <code>Win32API </code>function to expand the update region <code>InvalidateRgn()</code> or one of its more specific relatives. In most cases, the region to be invalidated has a rectangular shape, so in most cases, the function <code>InvalidateRect()</code> is used instead.</p>

<p>I already noted that the repainting itself is also more complex than just sending the message <code>WM_PAINT</code>:</p>

<ol>
	<li>	<p>First, the system asks the control to erase its background with the message <code>WM_ERASEBKGND</code>. This may be as soon as the region is invalidated. The parameter <code>wParam</code> is set to the window's device context, which can be used to paint something. However the painting, if used at all, should be very fast, and usually consists of only filling the area with some background brush, hence effectively erasing its background. If the control passes the message into <code>DefWindowProc()</code>, this is exactly what happens. <code>DefWindowProc()</code> simply gets the brush which was specified during window class registration (<code>WNDCLASS::hbrBackground</code>) and fills the control with it. Have you ever seen a grayish window on your screen when your machine is very busy with some very CPU-intensive tasks and you bring open a new window or bring a window to the top of the Z-order? Well, this is the reason. The grayish window has already received the <code>WM_ERASEBKGND</code> but not yet <code>WM_PAINT</code>. The return value is also important, the message should return non-zero if it performs the erase, or zero if it does not. (<code>DefWindowProc()</code> follows it and returns non-zero if it filled the control with the background brush, or zero if it did not because the <code>WNDCLASS::hbrBackground</code> was set to <code>NULL</code>.) We will see soon what it is good for.</p>
	</li>	<li>	<p>If the update region also intersects the non-client area of the window, the system sends <code>WM_NCPAINT</code>. For top-level windows, this message is responsible for painting window caption, the minimize and maximize buttons, and also the menu if the window has any. For child windows (i.e., controls), it is often used for painting a border and also scrollbars if the control supports them in a similar way as, for examples, the standard list-view and tree-view controls do. If the control just passes the message into <code>DefWindowProc()</code>, it paints a border as specified by the window style <code>WS_BORDER </code>and/or extended style <code>WS_EX_CLIENTEDGE</code> and the scrollbars as set by <code>SetScrollInfo()</code>. For today, we leave the <code>WM_NCPAINT</code> aside and we will return to it in a future article.</p>
	</li>	<li>	<p>Finally, the <code>WM_PAINT</code> is sent. However, note that the system treats this message specially and it comes only after all other messages from the message queue are handled and it is empty. If you think about it, it makes sense. As long as there are other messages in the queue, they may change the state of the control, resulting in a need for yet another repainting.</p>
	</li></ol>

<p>The system assumes that a control uses <code>BeginPaint()</code> and <code>EndPaint()</code> when handling <code>WM_PAINT</code>. Between the two calls, the application is expected to paint the whole invalid region of the control.</p>

<p>The first function, <code>BeginPaint()</code>, initializes the pointed structure <code>PAINTSTRUCT</code> and returns the device context (<code>HDC</code>) to be painted on (the same handle as stored in the structure). Two members are often very useful when handling the painting: the member <code>fErase</code>, which is set to <code>TRUE</code> if the window has <strong>not</strong> been erased with <code>WM_ERASEBKGND</code> (i.e., depending on the value that message has returned), and the member <code>rcPaint</code>, which is the smallest rectangle enclosing the invalid region which needs repainting.</p>

<p>The latter function, <code>EndPaint()</code>, frees any resources taken by <code>BeginPaint()</code> (e.g. the device context), and it also validates the invalid region, i.e., the invalid region of the control becomes empty after this call.</p>

<h2>The Flickering Problem</h2>

<p>Often, when a non-experienced control developer creates his first custom control, he is quite happy with it until he uses it in an application which resizes it together with the main window it resides in. When running it, he is then surprised by its ugly flickering. It is a wide-spread problem, so we will pay special attention to it.</p>

<p>If you already understand how Windows manages the painting from the section above, you probably already can see the culprit:</p>

<ul>
	<li>As the user is resizing the main application window, it gets <code>WM_SIZE</code> and in response it resizes the control.</li>	<li>The custom control's window procedure likely propagates its <code>WM_SIZE</code> into <code>DefWindowProc()</code>. That function (reasonably) invalidates the whole control, assuming its window class was registered with <code>CS_HREDRAW</code> and <code>CS_VREDRAW</code> as it commonly is.</li>	<li>In response to invalidation, the control gets <code>WM_ERASEBKGND</code> which by default fills the whole window client according to the brush used when registering its class.</li>	<li>Very soon then-after the control gets <code>WM_PAINT</code>, painting itself fully in all its glory.</li>	<li>As the user continues to resize the window by dragging the mouse, all of this happens again and again, causing the effect of flickering, how the control goes from erased to fully painted state and back again in short succession.</li></ul>

<h2>Solving the Flickering</h2>

<p>If you know the cause of the issue, it is quite easy to formulate hints for avoiding it. But let's list them here anyway for the sake of completeness. I tried to list the hints in the order of their importance (which, of course, is a subject of my personal preference to some degree).</p>

<ol>
	<li>	<p>If possible, do not rely on <code>WM_ERASEBKGND</code>, i.e., let it return non-zero without passing it into <code>DefWindowProc()</code>. Often, <code>WM_PAINT</code> can paint all the background of the dirty region and there is no need for such erasing.</p>
	</li>	<li>	<p>If you need to handle erasing specially from the painting itself, it can often be optimized so that <code>WM_ERASEBKGND</code> still does nothing but returns non-zero, and the handler of <code>WM_PAINT</code> can do the "erasing" by also painting the areas not covered by the regular paint code when <code>PAINTSTRUCT::fErase</code> is set.</p>
	</li>	<li>	<p>To the reasonable degree, try hard to design the painting code so that it does not repaint the same pixels multiple times. E.g., to paint blue rect with red border, do not <code>FillRect(red)</code> followed with <code>FillRect(blue)</code> to repaint the inner contents from red to blue. Rather paint the red border as 4 smaller rectangle not overlapped with the blue contents.</p>
	</li>	<li>	<p>For complex controls, the paint code may be often optimized to skip a lot of painting outside the invalid rectangle as specified by <code>PAINTSTRUCT::rcPaint</code>, by proper organizing the control data.</p>
	</li>	<li>	<p>When changing the control state, invalidate only the minimal required region of the control.</p>
	</li>	<li>	<p>When the flickering still happens during resizing, consider to not using <code>CS_HREDRAW</code> and <code>CS_VREDRAW</code>. Instead, invalidate the relevant parts of the control in handling the <code>WM_SIZE</code> manually. Often much smaller parts of the control may need repainting.</p>
	</li>	<li>	<p>When the control supports scrollbars, and using them leads to flickering, make sure the scrolling code uses <code>ScrollWindow()</code> function instead of invalidating whole control area. (Note we will cover the topic of scrolling in one of the sequel articles.)</p>
	</li>	<li>	<p>Generally, the flickering effect is also reduced when the painting performs better. If your paint method does not rely on the system setting the clipping rectangle to the client rectangle of the control, you may use window class style <code>CS_PARENTDC</code> when registering the control window class, leading to less work for <code>BeginPaint()</code>.</p>
	</li></ol>

<p>Note that although some of the points above may seem like a lot of work for a developer, it is very often a work which will be needed to be done anyway for a fully featured control which implements, for example, features like hit testing (<code>WM_HITTEST</code>). A lot of the code then may be reused. For example, consider a control which paints a table of some sort, each cell providing some interactive response when a user clicks in it. Then the code must be aware of the layout of the table, and the code computing the layout may be reused for the paint implementation and hit testing implementation.</p>

<p>In case everything above fails, there is also a magical band called <em>double buffering</em> which can solve the flickering in all cases (assuming the erasing via <code>WM_ERASEBKGND</code> is suppressed and delayed to <code>WM_PAINT</code>). But there is a prize for using it: higher resource consumption, especially memory. Even if your control still has the flickering problem after all you did in some situation, I recommend to use double-buffering only if the application explicitly requested for that (e.g., by specifying a style for it) because often the application never allows the situation when the flickering occurs (e.g., the application never resizes the control).</p>

<h2>Double Buffering</h2>

<p>Double buffering is a painting technique based on the fact that you may paint the code into a memory-based bitmap instead of directly on the screen, and then, after all the complex painting is done, you may copy (<em>blit</em>) the whole bitmap on the screen in a brisk.</p>

<p>Let's present a sample code of how it may look like. We start with the trivial control implementation and from the previous part, add the double buffering code:</p>

<pre lang="C++"><span class="code-comment">/*</span><span class="code-comment"> custom.h
 * (custom control interface)
 */</span>
 
<span class="code-comment">//</span><span class="code-comment"> ...</span>

<span class="code-comment">/*</span><span class="code-comment"> Style to request using double buffering. */</span>
<span class="code-preprocessor">#define XXS_DOUBLEBUFFER         (0x0001)
</span>
<span class="code-comment">//</span><span class="code-comment"> ...</span></pre>

<pre lang="C++"><span class="code-comment">/*</span><span class="code-comment"> custom.c
 * (custom control implementation)
 */</span>

<span class="code-keyword">#include</span><span class="code-preprocessor"> <span class="code-string">"</span><span class="code-string">custom.h"</span>
</span>
<span class="code-keyword">static</span> <span class="code-keyword">void</span>
CustomPaint(HWND hwnd, HDC hDC, RECT* rcDirty, BOOL bErase)
{
    <span class="code-comment">//</span><span class="code-comment"> ... Paint the control here.</span>
}

<span class="code-keyword">static</span> <span class="code-keyword">void</span>
CustomDoubleBuffer(HWND hwnd, PAINTSTRUCT* pPaintStruct)
{
    <span class="code-keyword">int</span> cx = pPaintStruct-&gt;rcPaint.right - pPaintStruct-&gt;rcPaint.left;
    <span class="code-keyword">int</span> cy = pPaintStruct-&gt;rcPaint.bottom - pPaintStruct-&gt;rcPaint.top;
    HDC hMemDC;
    HBITMAP hBmp;
    HBITMAP hOldBmp;
    POINT ptOldOrigin;

    <span class="code-comment">//</span><span class="code-comment"> Create new bitmap-back device context, large as the dirty rectangle.</span>
    hMemDC = CreateCompatibleDC(pPaintStruct-&gt;hdc);
    hBmp = CreateCompatibleBitmap(pPaintStruct-&gt;hdc, cx, cy);
    hOldBmp = SelectObject(hMemDC, hBmp);

    <span class="code-comment">//</span><span class="code-comment"> Do the painting into the memory bitmap.</span>
    OffsetViewportOrgEx(hMemDC, -(pPaintStruct-&gt;rcPaint.left),
                        -(pPaintStruct-&gt;rcPaint.top), &amp;ptOldOrigin);
    CustomPaint(hwnd, hMemDC, &amp;pPaintStruct-&gt;rcPaint, TRUE);
    SetViewportOrgEx(hMemDC, ptOldOrigin.x, ptOldOrigin.y, NULL);

    <span class="code-comment">//</span><span class="code-comment"> Blit the bitmap into the screen. This is really fast operation and although</span>
    <span class="code-comment">//</span><span class="code-comment"> the CustomPaint() can be complex and slow there will be no flicker any more.</span>
    BitBlt(pPaintStruct-&gt;hdc, pPaintStruct-&gt;rcPaint.left, pPaintStruct-&gt;rcPaint.top,
           cx, cy, hMemDC, <span class="code-digit">0</span>, <span class="code-digit">0</span>, SRCCOPY);

    <span class="code-comment">//</span><span class="code-comment"> Clean up.</span>
    SelectObject(hMemDC, hOldBmp);
    DeleteObject(hBmp);
    DeleteDC(hMemDC);
}

<span class="code-keyword">static</span> LRESULT CALLBACK
CustomProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    <span class="code-keyword">switch</span>(uMsg) {
        <span class="code-comment">//</span><span class="code-comment"> ...</span>

        <span class="code-keyword">case</span> WM_ERASEBKGND:
            <span class="code-keyword">return</span> FALSE;  <span class="code-comment">//</span><span class="code-comment"> Defer erasing into WM_PAINT</span>

        <span class="code-keyword">case</span> WM_PAINT:
        {
            PAINTSTRUCT ps;
            BeginPaint(hwnd, &amp;ps);
            <span class="code-keyword">if</span>(GetWindowLong(hwnd, GWL_STYLE) &amp; XXS_DOUBLEBUFFER)
                CustomDoubleBuffer(hwnd, &amp;ps);
            <span class="code-keyword">else</span>
                CustomPaint(hwnd, ps.hdc, &amp;ps.rcPaint, ps.fErase);
            EndPaint(hwnd, &amp;ps);
            <span class="code-keyword">return</span> <span class="code-digit">0</span>;
        }

        <span class="code-comment">//</span><span class="code-comment"> ...</span>
    }
    <span class="code-keyword">return</span> DefWindowProc(hwnd, uMsg, wParam, lParam);
}</pre>

<p>As it can be seen, the prototype of the function <code>CustomPaint()</code> has changed: It is now capable of painting the current control state to any device context, not just on the screen. The <code>BeginPaint()</code> and <code>EndPaint()</code> machinery has moved directly to the <code>WM_PAINT</code> handler. When double buffering is enabled (the control has the style <code>XXS_DOUBLEBUFFER</code>), the function <code>CustomDoubleBuffer()</code> is called to paint the control onto a temporary bitmap, which is then copied on the device context retrieved by <code>BeginPaint()</code>.</p>

<p>A few other things are worthy of any note as the code is quite self-explanatory:</p>

<ul>
	<li>	<p>When using double buffering, we always pass <code>bErase</code> as <code>TRUE</code> because, obviously, when double-buffered, the in-memory bitmap must be painted completely from scratch.</p>
	</li>	<li>	<p>As a small optimization, instead of allocating a bitmap for the complete control's client area, we allocate only as small as needed for the dirty region. Then we compensate the change in coordinates between the control's top left corner and the dirty rect's top left corner by arranging the proper view-port origin temporarily.</p>
	</li>	<li>	<p>The control creates and destroys the bitmap each time <code>WM_PAINT</code> is received. It is a potentially costly operation so this could be further optimized by some appropriate caching strategy of the bitmap for reuse. However, as the bitmap is potentially quite large and memory-hungry, you should not hold it all the time. In the real world, the control gets many <code>WM_PAINT</code> messages in a short period of time when the user is using it, or none for longer periods of time when he is not (e.g., when the application window is minimized) so the cache should be a bit smart. Something like that would make the example much longer and I believe the reader can take this as an opportunity for a small exercise of his own creativity.</p>
	</li></ul>

<p>(Again, an example Visual Studio 2010 project is attached. It is a slightly enhanced and more complete version of the code presented here.)</p>

<h2>Message WM_PRINTCLIENT</h2>

<p>There is yet another message worth mentioning, related to painting. The controls aspiring on a position of good citizen in the Windows environment should also support the message <code>WM_PRINTCLIENT</code>. In short, this message asks the control to paint itself into the provided device context (via <code>WPARAM</code>). Printing in Windows, for example, takes use of this. Various tools like screen zooming or thumbnailing utilities may use it. Some coding tricks like painting on a glass window border are possible by using this message (but that is out of our topic, at least for today).</p>

<p>Note our new version of <code>CustomPaint()</code> is exactly suitable for such purpose so implementing this message is a very straightforward task:</p>

<pre lang="C++"><span class="code-keyword">static</span> LRESULT CALLBACK
CustomProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    <span class="code-keyword">switch</span>(uMsg) {
        <span class="code-comment">//</span><span class="code-comment"> ...</span>

        <span class="code-keyword">case</span> WM_PRINTCLIENT:
        {
            RECT rc;
            GetClientRect(hwnd, &amp;rc);
            CustomPaint(hwnd, (HDC) wParam, &amp;rc, TRUE);
            <span class="code-keyword">return</span> <span class="code-digit">0</span>;
        }

        <span class="code-comment">//</span><span class="code-comment"> ...</span>
    }
    <span class="code-keyword">return</span> DefWindowProc(hwnd, uMsg, wParam, lParam);
}</pre>

<h2>Next Time: Visual Styles</h2>

<p>I omitted talking about one API closely related to painting of controls. It is an API which provides support for <em>visual themes</em> (implemented by <em>UXTHEME.DLL</em>). As it was introduced in Windows XP, it is sometimes also referred as <em>XP theming</em>. In these days, the controls simply must be theme-aware if they want to fit into the Windows look and feel.</p>

<p>Though, it is quite a complex topic of its own, so the next time a whole article will be dedicated to it.</p>


						</div>
						

						<div class="float-right" style="margin:20px 0 0 10px;border:1px solid #ccc">
						
						</div>
                        
                        
						
						<h2>License</h2>
						<div id="LicenseTerms"><p>This article, along with any associated source code and files, is licensed under <a href="http://www.codeproject.com/info/cpol10.aspx" rel="license">The Code Project Open License (CPOL)</a></p></div><h2 id="ctl00_AboutHeading">About the Author</h2>
						    

<div class="author-wrapper">

    <div class="pic-wrapper"> 
        <img id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_memberPhoto" class="profile-pic" src="./Custom Controls in Win32 API_ The Painting - CodeProject_files/58de2d085c17e28b8951315245dd408c.jpeg" style="border-width:0px;transform:rotate(1deg);">
    </div>

    <div class="container-member">  
        <b><a id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_memberProfileLink" class="author" href="https://www.codeproject.com/Members/Martin-Mitas">Martin Mitáš</a></b>

        <table>
        <tbody><tr>
            <td rowspan="2" nowrap="" valign="middle">
            <div id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowOn" class="follow">
	            
	            
	            <a href="https://www.linkedin.com/profile/view?id=88607525"><img style="vertical-align:middle;border:0;height:24px;width:24px" alt="LinkedIn" src="./Custom Controls in Win32 API_ The Painting - CodeProject_files/linkedin-32.png"></a> 
            </div>
            </td>
            <td nowrap="nowrap">
                <div class="company">
                    <span id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_memberJobTitle">Team Leader</span>
	                <span id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_memberCompany"></span>
                </div>
            </td>
            <td rowspan="2" style="padding-left:15px">
                <a id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowMember_FollowBtn" title="Have events related to this Member appear in your timeline" class="button unfollowed align-center invisible" data-enabletooltip="true" data-tooltip="Have the articles and posts from this member appear in your Timeline so you can stay up to date." style="display:none;">Follow<div class="tiny-text" style="margin-top:-3px;">this Member</div></a>
	<a id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowMember_UnfollowBtn" title="Unfollow this Member" class="button followed align-center invisible" data-enabletooltip="true" data-tooltip="Stop following this Member" style="display:none;">Unfollow</a>

            </td>
        </tr>
        <tr>
            <td>
                <span id="ctl00_AboutAuthorRptr_ctl00_AboutAuthor_memberLocation">Czech Republic <img src="./Custom Controls in Win32 API_ The Painting - CodeProject_files/CZ.gif" alt="Czech Republic" width="16px" height="11px"></span>
            </td>
        </tr>
        </tbody></table>
    </div>

    <div class="description">
        No Biography provided

        
    </div>

</div><br>
						
						

						<div class="clearfix"></div>

						<div style="padding-top:8px">
							
						</div>

					

				    
					</form>

				</div>

				
				<div class="bottom-promo"> 
				    
				</div>
				

                

				
				

					<h2>Comments and Discussions</h2>
					
					<p><img alt="Comment" src="./Custom Controls in Win32 API_ The Painting - CodeProject_files/NewComment.gif" width="12px" height="16px">
					<b>24 messages</b> have been posted for this article 
					Visit <b><a id="ctl00_ArticleLink" href="https://www.codeproject.com/Articles/617212/Custom-Controls-in-Win-API-The-Painting">https://www.codeproject.com/Articles/617212/Custom-Controls-in-Win-API-The-Painting</a></b> to post and view comments on 
					this article, or click <b><a id="ctl00_PrintWithMessage" href="https://www.codeproject.com/Articles/617212/Custom-Controls-in-Win-API-The-Painting?display=PrintAll">here</a></b> 
					to get a print view with messages.</p>
					
				

			</div>
			
		</td>
		<td width="170px" class="article-wing-right">
			
		</td>
		</tr></tbody></table>

		
		<div class="theme1-background" style="height:2px" id="stickyStop"></div>

		<div class="extended tiny-text">
			<div class="row">
				<div class="float-left">
					<a id="ctl00_PermaLink" href="https://www.codeproject.com/Articles/617212/Custom-Controls-in-Win-API-The-Painting">Permalink</a> | 
					<a id="ctl00_AdvertiseLink" href="http://developermedia.com/">Advertise </a> |
					<a id="ctl00_PrivacyLink" href="https://www.codeproject.com/info/privacy.aspx">Privacy</a> |
    				<a id="ctl00_CookiePolicyLink" href="https://www.codeproject.com/info/cookies.aspx">Cookies</a> |
                    <a id="ctl00_TermsOfUseLink" href="https://www.codeproject.com/info/TermsOfUse.aspx">Terms of Use</a> |
					<a id="ctl00_Mobile">Mobile</a>
					<br>
								
					
					Web06 |
					2.8.181119.1 |
					Last Updated 12 Dec 2014								
				</div>

                      

				<div class="float-right align-right">
					Article Copyright 2013 by Martin Mitáš<br>Everything else
					Copyright © <a href="mailto:webmaster@codeproject.com">CodeProject</a>, 1999-2018 <br>
				</div>

				

			</div>
		</div>
		

		<br clear="all">
		
			

	</div> 
	</div>
</div>






<script type="text/javascript" src="./Custom Controls in Win32 API_ The Painting - CodeProject_files/MemberProfilePopup.min.js.下载"></script>
<script type="text/javascript">//<![CDATA[
$(document).ready(function () {
   processCodeBlocks.Initialise('#contentdiv');
   thumbnailer.Initialise('#contentdiv',700,600);
});
cookieconsent.initialise({
                                enabled : true,
                                cookie  : { domain: 'codeproject.com' },
                                palette : {
                                    popup: { background: '#ff9900' },
                                    button: { background: '#f5d948' }
                                },
                                law :  {
                                    showForAllRegions : true, 
                                    countryCode : 'CN' 
                                },
                                theme: 'edgeless',
                                type : 'opt-in',
                                content: {
                                    message: 'Like every other website we use cookies. By using our site you acknowledge that you have read and understand our <a href=\'/info/cookie.aspx\'>Cookie Policy</a>, <a href=\'/info/privacy.aspx\'>Privacy Policy</a>, and our <a href=\'/info/TermsOfUse.aspx\'>Terms of Service</a>.',
                                    href:    'https://www.codeproject.com/info/privacy.aspx'
                                },
                                revokable:true,
                                onStatusChange: function(status) {
                                    $.ajax({
                                		dataType  : 'json',
                                        data: JSON.stringify({ allowCookies : this.hasConsented() }),
                                        url: '/script/Common/webservices/CommonServices.aspx/SetCookieConsent',
                                        cache: false,
                                        type: 'POST',
                                        contentType: 'application/json'
                                    })
                                    console.log(this.hasConsented() ? 'enable cookies' : 'disable cookies');
                                    console.log(this.hasAnswered() ? 'has answered' : 'did not answer');
                                },
                            });
$(document).ready(function() { anchorAnimate();
});
$(document).ready(function(){
    $('#__EVENTVALIDATION').attr('autocomplete', 'off');
});
$(function() {
                        var followServicectl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowMember = new FollowService('/script/follow/webservices/followServices.aspx/', true);
                        followServicectl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowMember.initFollowObjectButtons({
                            item : { 
                                objectTypeId   : 1,
                                objectId       : 5807385
                            },
                            followButtonId   : 'ctl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowMember_FollowBtn',
                            unfollowButtonId : 'ctl00_AboutAuthorRptr_ctl00_AboutAuthor_FollowMember_UnfollowBtn'
                        }, false);
                    });

//]]>
</script>





<div id="MemberProfilePopupDiv" class="raised box" style="display: none; position: absolute;"></div><div id="MemberProfilePopupDiv" class="raised box" style="display: none; position: absolute;"></div><div id="MemberProfilePopupDiv" class="raised box" style="display: none; position: absolute;"></div></body></html>